structure Tokens = Tokens

type pos = int
type varIndex = int
type varString = string
type svalue = Tokens.svalue
type ('a,'b) token = ('a,'b) Tokens.token
type lexresult  = (svalue,pos) token

val pos = ref 0
val varIndex = ref 0
val varString = ref ""
val eof = fn () => Tokens.EOF(!pos,!pos)
val error = fn x => TextIO.output(TextIO.stdOut,x ^ "\n")

(* hash table from string to int - to store the variables found during parse *)
structure StrTbl = 
      HashTableFn(struct
                    type hash_key = string
                    val hashVal = HashString.hashString
                    val sameKey = (op=) : string * string -> bool
				  end)

(* the hash table indetifier *)				  
val varTable : int StrTbl.hash_table = StrTbl.mkTable(10, Fail "Not found")

(* if variable was already encountered - returns its integer index, 
   otherwise assigns variable with a fresh index and returns this index *)
fun getVarIndex (varId : string, varTable : int StrTbl.hash_table) = 
	let
		fun newVarIndex(varId : string, varTable : int StrTbl.hash_table) =
			let
				val _ = varIndex := !varIndex + 1;
				val _ = (StrTbl.insert varTable (varId, !varIndex)); 
				val _ = (varString := (!varString^varId^" = "^Int.toString(!varIndex)^"\n"))
			in
				getVarIndex(varId, varTable)
			end;
	in
		case (StrTbl.find varTable varId) of SOME index => index
										   | NONE       => newVarIndex(varId, varTable)
	end;

val DEBUG = true;
%%
%header (functor BJKLexFun(structure Tokens : BJK_TOKENS));

alpha=[A-Za-z];
digit=[0-9];
alphanum=[A-Za-z0-9];
ws = [\ \t];
%%
"%".*"\n"     => (pos := (!pos) + 1; lex());
\n            => (pos := (!pos) + 1; lex());
{ws}+         => (lex());
[lL]"oop"     => (Tokens.LOOP(!pos,!pos));
[iI]"f" 	  => (Tokens.IF(!pos,!pos));
[cC]"hoose"   => (Tokens.CHOOSE(!pos,!pos));
[eE]"lse"     => (Tokens.ELSE(!pos,!pos));
[oO]"r"		  => (Tokens.OR(!pos,!pos));
[sS]"kip"     => (Tokens.SKIP(!pos,!pos));
{alpha}{alphanum}+ => (Tokens.VAR(getVarIndex(yytext, varTable), !pos,!pos));
";"      	  => (Tokens.SEMI(!pos,!pos));
"{"        	  => (Tokens.LPAREN(!pos,!pos));
"0"		   	  => (Tokens.ZERO(!pos,!pos));
"}"        	  => (Tokens.RPAREN(!pos,!pos));
"("		   	  => (Tokens.LBRACE(!pos,!pos));
")"		   	  => (Tokens.RBRACE(!pos,!pos));
"+"        	  => (Tokens.PLUS(!pos,!pos));
"*"        	  => (Tokens.TIMES(!pos,!pos));
":="	   	  => (Tokens.ASSIGN(!pos,!pos));
.		   	  => (error ("Parser: ignoring bad character "^yytext); lex());
